package om.recorder;

import ohos.media.audio.AudioCapturer;
import ohos.media.audio.GainControlEffect;
import ohos.media.audio.NoiseSuppressorEffect;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * An {@code PullableSource} represents {@link Source} which is Pullable
 *
 * @author Kailash Dabhi
 * @date 01-07-2017
 */
public interface PullableSource extends Source {
    /**
     * pullSizeInBytes
     *
     * @return number of bytes to be read from @{@link Source}
     */
    int pullSizeInBytes();

    void isEnableToBePulled(boolean enabledToBePulled);

    boolean isEnableToBePulled();

    AudioCapturer preparedToBePulled();

    class Base implements PullableSource {
        private final PullableSource pullableSource;

        Base(PullableSource pullableSource) {
            this.pullableSource = pullableSource;
        }

        @Override
        public AudioCapturer audioRecord() {
            return pullableSource.audioRecord();
        }

        @Override
        public AudioRecordConfig config() {
            return pullableSource.config();
        }

        @Override
        public int minimumBufferSize() {
            return pullableSource.minimumBufferSize();
        }

        @Override
        public int pullSizeInBytes() {
            return pullableSource.pullSizeInBytes();
        }

        @Override
        public void isEnableToBePulled(boolean enabledToBePulled) {
            pullableSource.isEnableToBePulled(enabledToBePulled);
        }

        @Override
        public boolean isEnableToBePulled() {
            return pullableSource.isEnableToBePulled();
        }

        @Override
        public AudioCapturer preparedToBePulled() {
            return pullableSource.preparedToBePulled();
        }
    }

    class Default extends Source.Default implements PullableSource {
        private final int pullSizeInBytes;
        private volatile boolean pull;

        public Default(AudioRecordConfig config, int pullSizeInBytes) {
            super(config);
            this.pullSizeInBytes = pullSizeInBytes;
        }

        public Default(AudioRecordConfig config) {
            super(config);
            this.pullSizeInBytes = minimumBufferSize();
        }

        @Override
        public int pullSizeInBytes() {
            return pullSizeInBytes;
        }

        @Override
        public void isEnableToBePulled(boolean enabledToBePulled) {
            this.pull = enabledToBePulled;
        }

        @Override
        public boolean isEnableToBePulled() {
            return pull;
        }

        @Override
        public AudioCapturer preparedToBePulled() {
            final AudioCapturer audioRecord = audioRecord();
            audioRecord.start();
            isEnableToBePulled(true);
            return audioRecord;
        }
    }

    class NoiseSuppressor extends Base {
        public NoiseSuppressor(PullableSource pullableSource) {
            super(pullableSource);
        }

        @Override
        public AudioCapturer preparedToBePulled() {
            if (NoiseSuppressorEffect.isAvailable()) {
                NoiseSuppressorEffect noiseSuppressorEffect = NoiseSuppressorEffect.create(audioRecord().getCapturerSessionId(), "");
                if (noiseSuppressorEffect != null) {
                    noiseSuppressorEffect.setActivated(true);
                    Logger.getLogger(getClass().getSimpleName()).log(Level.SEVERE, "NoiseSuppressorEffect ON");
                } else {
                    Logger.getLogger(getClass().getSimpleName()).log(Level.SEVERE, "NoiseSuppressorEffect failed :(");
                }
            } else {
                Logger.getLogger(getClass().getSimpleName()).log(Level.SEVERE, "This device don't support NoiseSuppressorEffect");
            }
            return super.preparedToBePulled();
        }
    }

    class AutomaticGainControl extends Base {
        public AutomaticGainControl(PullableSource pullableSource) {
            super(pullableSource);
        }

        @Override
        public AudioCapturer preparedToBePulled() {
            if (GainControlEffect.isAvailable()) {
                GainControlEffect gainControlEffect = GainControlEffect.create(audioRecord().getCapturerSessionId(), "");
                if (gainControlEffect != null) {
                    gainControlEffect.setActivated(true);
                    Logger.getLogger(getClass().getSimpleName()).log(Level.SEVERE, "GainControlEffect ON");
                } else {
                    Logger.getLogger(getClass().getSimpleName()).log(Level.SEVERE, "GainControlEffect failed :(");
                }
            } else {
                Logger.getLogger(getClass().getSimpleName()).log(Level.SEVERE, "This device don't support GainControlEffect");
            }
            return super.preparedToBePulled();
        }
    }
}